#!/bin/bash
###############################################################################
#       脚本名称: test_logger_file.sh
#       功能描述: 文件日志输出器单元测试
#       作者: 林再来
#       日期: 2025-10-28
#       版本: 1.0
#       功能:
#           1、测试.log格式日志文件写入
#           2、测试.json格式日志文件写入
#           3、测试日志文件轮转功能（按大小、按时间）
#           4、测试文件权限和目录创建
#           5、测试并发写入安全性（文件锁）
#           6、测试日志压缩功能
#       依赖(插件/命令):
#           flock（文件锁）
#           gzip（压缩，可选）
###############################################################################

# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"

# 加载测试框架
source "$SCRIPT_DIR/../test_framework.sh"

# 加载被测模块
source "$PROJECT_ROOT/scripts/logger/appender/appender_file.sh"
source "$PROJECT_ROOT/scripts/logger/formatter/formatter_plain.sh"
source "$PROJECT_ROOT/scripts/logger/formatter/formatter_json.sh"

# 测试目录
TEST_LOG_DIR="$PROJECT_ROOT/temp/test_logs"

###############################################################################
# 测试准备和清理
###############################################################################

function setup_test_env() {
    # 创建测试目录
    mkdir -p "$TEST_LOG_DIR"
}

function cleanup_test_env() {
    # 清理测试文件
    rm -rf "$TEST_LOG_DIR"
}

###############################################################################
# 测试用例
###############################################################################

#-----------------------------------------------------------------------------
# 测试: 文件输出器初始化
#-----------------------------------------------------------------------------
function test_file_init() {
    local appender_name="test_file_init"
    
    _appender_file_init "$appender_name"
    
    # 验证配置已设置
    local file="${_FILE_APPENDER_CONFIGS[${appender_name}_file]}"
    local max_size="${_FILE_APPENDER_CONFIGS[${appender_name}_max_size]}"
    
    assert_not_empty "$file" "文件路径配置不应为空"
    assert_not_empty "$max_size" "最大大小配置不应为空"
    
    _appender_file_close "$appender_name"
}

#-----------------------------------------------------------------------------
# 测试: .log格式日志文件写入
#-----------------------------------------------------------------------------
function test_file_write_log_format() {
    setup_test_env
    
    local appender_name="test_log_writer"
    local log_file="$TEST_LOG_DIR/test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入纯文本格式日志
    local formatted="[INFO] 2025-10-28 10:00:00 - 这是一条测试日志"
    _appender_file_write "$appender_name" "$formatted"
    
    # 验证文件已创建
    assert_file_exists "$log_file" "日志文件应该被创建"
    
    # 验证文件内容
    local content
    content=$(cat "$log_file")
    assert_contains "$content" "这是一条测试日志" "文件应包含日志消息"
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: .json格式日志文件写入
#-----------------------------------------------------------------------------
function test_file_write_json_format() {
    setup_test_env
    
    local appender_name="test_json_writer"
    local log_file="$TEST_LOG_DIR/test.json"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入JSON格式日志
    local json_log='{"timestamp":"2025-10-28 10:00:00","level":"INFO","message":"JSON测试消息"}'
    _appender_file_write "$appender_name" "$json_log"
    
    # 验证文件已创建
    assert_file_exists "$log_file" "JSON日志文件应该被创建"
    
    # 验证文件内容是有效的JSON
    local content
    content=$(cat "$log_file")
    assert_contains "$content" "JSON测试消息" "文件应包含JSON消息"
    assert_contains "$content" "timestamp" "文件应包含timestamp字段"
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 自动创建目录
#-----------------------------------------------------------------------------
function test_file_auto_create_directory() {
    setup_test_env
    
    local appender_name="test_auto_dir"
    local log_file="$TEST_LOG_DIR/subdir1/subdir2/test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入日志（应自动创建目录）
    _appender_file_write "$appender_name" "[INFO] 测试自动创建目录"
    
    # 验证目录已创建
    assert_dir_exists "$(dirname "$log_file")" "目录应被自动创建"
    assert_file_exists "$log_file" "日志文件应该被创建"
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 文件大小解析
#-----------------------------------------------------------------------------
function test_file_parse_size() {
    # 测试大小字符串解析
    local size_1k=$(_parse_size "1K")
    assert_equals "1024" "$size_1k" "1K应该等于1024字节"
    
    local size_1m=$(_parse_size "1M")
    assert_equals "1048576" "$size_1m" "1M应该等于1048576字节"
    
    local size_1g=$(_parse_size "1G")
    assert_equals "1073741824" "$size_1g" "1G应该等于1073741824字节"
    
    local size_100=$(_parse_size "100")
    assert_equals "100" "$size_100" "纯数字应保持不变"
}

#-----------------------------------------------------------------------------
# 测试: 获取文件大小
#-----------------------------------------------------------------------------
function test_file_get_size() {
    setup_test_env
    
    local test_file="$TEST_LOG_DIR/size_test.txt"
    
    # 创建测试文件
    echo "Hello World" > "$test_file"
    
    # 获取文件大小
    local size=$(_get_file_size "$test_file")
    
    # 验证返回了大小（应该是12字节：11个字符+换行符）
    assert_not_empty "$size" "文件大小不应为空"
    assert_matches "$size" "^[0-9]+$" "文件大小应该是数字"
    
    # 测试不存在的文件（应返回0）
    local nonexist_size=$(_get_file_size "/nonexistent/file.txt")
    assert_equals "0" "$nonexist_size" "不存在的文件大小应为0"
    
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 按大小轮转
#-----------------------------------------------------------------------------
function test_file_rotation_by_size() {
    setup_test_env
    
    local appender_name="test_size_rotation"
    local log_file="$TEST_LOG_DIR/rotation_test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    _appender_file_set_config "$appender_name" "max_size" "1K"  # 1KB触发轮转
    _appender_file_set_config "$appender_name" "rotation_strategy" "size"
    _appender_file_set_config "$appender_name" "max_files" "3"
    _appender_file_set_config "$appender_name" "compress" "false"
    
    # 写入足够多的日志触发轮转
    for i in {1..50}; do
        _appender_file_write "$appender_name" "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - 测试日志行${i} - 填充数据填充数据填充数据"
    done
    
    # 验证原文件仍存在
    assert_file_exists "$log_file" "主日志文件应该存在"
    
    # 验证轮转文件是否创建（可能有.1、.2等）
    # 注意：轮转可能还未发生，取决于日志大小
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 文件权限设置
#-----------------------------------------------------------------------------
function test_file_permissions() {
    setup_test_env
    
    local appender_name="test_permissions"
    local log_file="$TEST_LOG_DIR/perm_test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    _appender_file_set_config "$appender_name" "file_mode" "0644"
    
    # 写入日志创建文件
    _appender_file_write "$appender_name" "[INFO] 测试文件权限"
    
    # 验证文件存在
    assert_file_exists "$log_file" "日志文件应该被创建"
    
    # 验证文件权限（注意：权限检查在某些系统可能不准确）
    if [[ -f "$log_file" ]]; then
        local perms=$(stat -c "%a" "$log_file" 2>/dev/null || stat -f "%Lp" "$log_file" 2>/dev/null)
        # 权限可能是644或644（取决于系统）
        # 只验证文件确实可读写
        [[ -r "$log_file" ]] && [[ -w "$log_file" ]]
    fi
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 连续多次写入
#-----------------------------------------------------------------------------
function test_file_multiple_writes() {
    setup_test_env
    
    local appender_name="test_multi_write"
    local log_file="$TEST_LOG_DIR/multi_write.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    local count=20
    
    # 连续写入多条日志
    for ((i=1; i<=count; i++)); do
        _appender_file_write "$appender_name" "[INFO] 测试消息 $i"
    done
    
    # 验证所有日志都写入
    local line_count
    line_count=$(wc -l < "$log_file")
    
    assert_equals "$count" "$line_count" "应该写入${count}行日志"
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 文件锁功能
#-----------------------------------------------------------------------------
function test_file_locking() {
    setup_test_env
    
    local appender_name="test_lock"
    local log_file="$TEST_LOG_DIR/lock_test.log"
    local lock_file="${log_file}.lock"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入日志
    _appender_file_write "$appender_name" "[INFO] 测试文件锁"
    
    # 验证日志文件存在
    assert_file_exists "$log_file" "日志文件应该存在"
    
    # 锁文件在写入完成后应该仍然存在（用于下次写入）
    # 注意：锁文件的存在性取决于实现
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 日志刷新
#-----------------------------------------------------------------------------
function test_file_flush() {
    setup_test_env
    
    local appender_name="test_flush"
    local log_file="$TEST_LOG_DIR/flush_test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入日志
    _appender_file_write "$appender_name" "[INFO] 测试刷新"
    
    # 执行刷新
    _appender_file_flush "$appender_name"
    local flush_result=$?
    
    assert_equals "0" "$flush_result" "刷新操作应该成功"
    
    # 验证文件内容仍然存在
    assert_file_exists "$log_file" "刷新后文件应该存在"
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 文件关闭和清理
#-----------------------------------------------------------------------------
function test_file_close() {
    setup_test_env
    
    local appender_name="test_close"
    local log_file="$TEST_LOG_DIR/close_test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入日志
    _appender_file_write "$appender_name" "[INFO] 测试关闭"
    
    # 关闭appender
    _appender_file_close "$appender_name"
    
    # 验证配置已清理
    local file_config="${_FILE_APPENDER_CONFIGS[${appender_name}_file]:-}"
    assert_empty "$file_config" "关闭后配置应该被清理"
    
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 大文件写入性能
#-----------------------------------------------------------------------------
function test_file_large_writes() {
    setup_test_env
    
    local appender_name="test_large"
    local log_file="$TEST_LOG_DIR/large_test.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 写入较大的日志消息
    local large_msg="$(printf '=%.0s' {1..1000})"  # 1000个等号
    
    for i in {1..10}; do
        _appender_file_write "$appender_name" "[INFO] ${large_msg}"
    done
    
    # 验证文件存在且有内容
    assert_file_exists "$log_file" "大文件应该被创建"
    
    local size=$(_get_file_size "$log_file")
    # 文件应该至少有10KB（10行 * 1000字符）
    if [[ $size -lt 10000 ]]; then
        echo "大文件大小不足: $size 字节" >&2
        return 1
    fi
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: .log和.json两种格式混合使用
#-----------------------------------------------------------------------------
function test_file_mixed_formats() {
    setup_test_env
    
    # 同时写入.log和.json文件
    local log_appender="test_log"
    local json_appender="test_json"
    
    local log_file="$TEST_LOG_DIR/mixed.log"
    local json_file="$TEST_LOG_DIR/mixed.json"
    
    # 初始化两个appender
    _appender_file_init "$log_appender"
    _appender_file_set_config "$log_appender" "file" "$log_file"
    
    _appender_file_init "$json_appender"
    _appender_file_set_config "$json_appender" "file" "$json_file"
    
    # 写入相同内容的不同格式
    local timestamp="2025-10-28 10:00:00"
    local message="混合格式测试"
    
    _appender_file_write "$log_appender" "[INFO] $timestamp - $message"
    _appender_file_write "$json_appender" "{\"timestamp\":\"$timestamp\",\"level\":\"INFO\",\"message\":\"$message\"}"
    
    # 验证两个文件都创建了
    assert_file_exists "$log_file" ".log文件应该被创建"
    assert_file_exists "$json_file" ".json文件应该被创建"
    
    # 验证内容
    local log_content
    local json_content
    log_content=$(cat "$log_file")
    json_content=$(cat "$json_file")
    
    assert_contains "$log_content" "$message" ".log文件应包含消息"
    assert_contains "$json_content" "$message" ".json文件应包含消息"
    
    _appender_file_close "$log_appender"
    _appender_file_close "$json_appender"
    cleanup_test_env
}

#-----------------------------------------------------------------------------
# 测试: 特殊字符和编码
#-----------------------------------------------------------------------------
function test_file_special_characters() {
    setup_test_env
    
    local appender_name="test_special"
    local log_file="$TEST_LOG_DIR/special.log"
    
    _appender_file_init "$appender_name"
    _appender_file_set_config "$appender_name" "file" "$log_file"
    
    # 包含特殊字符的日志
    local special_chars="中文字符 Special chars: @#\$%^&*()[]{}|\\;:'\",<>?"
    _appender_file_write "$appender_name" "[INFO] $special_chars"
    
    # 验证文件存在
    assert_file_exists "$log_file" "文件应该被创建"
    
    # 验证内容
    local content
    content=$(cat "$log_file")
    assert_contains "$content" "中文字符" "应该包含中文字符"
    
    _appender_file_close "$appender_name"
    cleanup_test_env
}

###############################################################################
# 运行所有测试
###############################################################################

function run_all_tests() {
    test_suite_start "文件输出器单元测试"
    
    run_test "文件输出器初始化" test_file_init
    run_test ".log格式日志文件写入" test_file_write_log_format
    run_test ".json格式日志文件写入" test_file_write_json_format
    run_test "自动创建目录" test_file_auto_create_directory
    run_test "文件大小解析" test_file_parse_size
    run_test "获取文件大小" test_file_get_size
    run_test "按大小轮转" test_file_rotation_by_size
    run_test "文件权限设置" test_file_permissions
    run_test "连续多次写入" test_file_multiple_writes
    run_test "文件锁功能" test_file_locking
    run_test "日志刷新" test_file_flush
    run_test "文件关闭和清理" test_file_close
    run_test "大文件写入性能" test_file_large_writes
    run_test ".log和.json混合格式" test_file_mixed_formats
    run_test "特殊字符和编码" test_file_special_characters
    
    test_suite_end
}

# 主函数
function main() {
    run_all_tests
    test_report
    exit_with_test_result
}

# 如果直接执行此脚本，运行所有测试
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main
fi

